﻿using CustomCharacter.VoiceChat;
using Exiled.API.Enums;
using Exiled.API.Features;
using Exiled.Events.EventArgs.Player;
using MEC;
using PlayerRoles;
using Respawning;
using RgCore.GameData;
using RgCore.PlayerHud;
using Subtitles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using CustomCharacter.Interfaces;
using RgCore.CustomSide;
using UnityEngine;
using Utils.Networking;
using VoiceChat;
using Log = Exiled.API.Features.Log;
using RgCore.GameModes;

namespace CustomCharacter
{
    public static class EventHandlers
    {
        public static void RegisterEvents()
        {
            Exiled.Events.Handlers.Player.Dying += Player_Dying;
            Exiled.Events.Handlers.Player.ChangingSpectatedPlayer += Player_ChangingSpectatedPlayer;
            Exiled.Events.Handlers.Player.InteractingDoor += Player_InteractingDoor;
            Exiled.Events.Handlers.Player.ChangingRole += Player_ChangingRole;
            Exiled.Events.Handlers.Player.Handcuffing += Player_Handcuffing;
            Exiled.Events.Handlers.Player.TogglingNoClip += Player_Noclip;
            Exiled.Events.Handlers.Player.Died += Player_Died;
            Exiled.Events.Handlers.Player.EnteringPocketDimension += Player_EnteringPocketDimension;
            RgCore.RgCore.RoundStarted += Server_RoundStarted;
            Exiled.Events.Handlers.Server.RespawningTeam += Server_RespawningTeam;
            Exiled.Events.Handlers.Server.RestartingRound += Server_RestartingRound;
            Exiled.Events.Handlers.Server.RoundEnded += Server_RoundEnded;
            Exiled.Events.Handlers.Player.Verified += Player_Verified;
            Exiled.Events.Handlers.Player.Escaping += Player_Escaping;
            Exiled.Events.Handlers.Player.Left += Player_Left;
        }
        private static void Player_Dying(DyingEventArgs ev)
        {

        }
        private static void Player_ChangingSpectatedPlayer(ChangingSpectatedPlayerEventArgs ev)
        {
            if (!ev.Player.HasMsg("spectator"))
                ev.Player.SendRawMsg("spectator", CustomCharacter.SpectatorHud, 0, ScreenLocation.Bottom, false);
        }
        private static void Player_ChangingRole(ChangingRoleEventArgs ev)
        {
            if (ev.Player.Role == RoleTypeId.Scp939)
                ev.Player.VC_ResetPrimaryChannel();
            Timing.CallDelayed(1.0f, delegate ()
            {
                if (ev.Player.IsAlive)
                {
                    var instance = ev.Player.GetCharacterInstance();
                    if (instance != null)
                    {
                        ev.Player.MaxHealth = instance.Attribute.MaxHealth;
                        ev.Player.Health = ev.Player.MaxHealth;
                    }
                }
                foreach (var cc in CustomCharacter.AllCharacters)
                {
                    CustomCharacter.UpdateCustomInfo(cc);
                }
            });
        }
        private static void Player_Handcuffing(HandcuffingEventArgs ev)
        {
            if (ev.Player != null && ev.Target != null && ev.Player.IsFriendly(ev.Target))
                ev.IsAllowed = false;
        }

        private static void Player_Died(Exiled.Events.EventArgs.Player.DiedEventArgs ev)
        {
            try
            {
                if (ev.TargetOldRole == RoleTypeId.Scp939)
                    ev.Player.VC_ResetPrimaryChannel();
                CustomCharacter cc = ev.Player.GetCharacterInstance();
                if (cc == null)
                    return;
                cc.Role_Deactive();
                CustomCharacter.AllCharacters.Remove(cc);
                Timing.CallDelayed(1.0f, delegate ()
                {
                    ev.Player.CustomInfo = " ";
                    ev.Player.InfoArea = PlayerInfoArea.Role | PlayerInfoArea.Badge | PlayerInfoArea.Nickname;
                });
                if (!(cc is ISubProject))
                {
                    if (cc is IScpNumber num)
                    {
                        var custom = MethodExtensions.GetCustomDeathAnnouncement(num, ev.DamageHandler.Base);
                        RespawnEffectsController.PlayCassieAnnouncement(custom.Announcement, false, false);
                        new SubtitleMessage(custom.SubtitleParts).SendToAuthenticated();
                    }
                    else
                    {
                        var word = MethodExtensions.GetCustomDeathAnnouncement(cc.Attribute.Name, ev.DamageHandler.Base);
                        RespawnEffectsController.PlayCassieAnnouncement(word, false, false, true);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }

        private static void Player_EnteringPocketDimension(Exiled.Events.EventArgs.Player.EnteringPocketDimensionEventArgs ev)
        {
            ev.IsAllowed = !ev.Scp106.IsFriendly(ev.Player);
        }

        private static void Player_Escaping(EscapingEventArgs ev)
        {
            if (ev.Player.GetSide() ==Side.Scp)
                ev.IsAllowed = false;
        }
        private static void Player_Noclip(TogglingNoClipEventArgs ev)
        {
            CustomCharacter cc = ev.Player.GetCharacterInstance();
            if (cc != null && cc is IVoiceChannelModifcation vc)
            {
                if (vc.PrimaryModification)
                {
                    if (VoiceChatManager.PrimaryChannelModifier.TryGetValue(ev.Player, out var current))
                    {
                        int index = vc.AvailableVoiceChannels.IndexOf(current);
                        index++;
                        if (index < vc.AvailableVoiceChannels.Length)
                            ev.Player.VC_SetPrimaryChannel(vc.AvailableVoiceChannels[index]);
                        else
                            ev.Player.VC_ResetPrimaryChannel();
                    }
                    else
                        ev.Player.VC_SetPrimaryChannel(vc.AvailableVoiceChannels[0]);
                }
                else
                {
                    var sender = ev.Player.VC_GetSender();
                    if (sender.Intersect(vc.AvailableVoiceChannels).All(x => vc.AvailableVoiceChannels.Contains(x))) //开启状态
                    {
                        foreach (var channel in vc.AvailableVoiceChannels)
                            ev.Player.VC_RemoveSender(channel);
                    }
                    else
                    {
                        foreach (var channel in vc.AvailableVoiceChannels)
                            ev.Player.VC_AddSender(channel, false);
                    }
                }
            }
            else if (ev.Player.Role.Type == RoleTypeId.Scp939)
            {
                if (VoiceChatManager.PrimaryChannelModifier.ContainsKey(ev.Player))
                {
                    ev.Player.VC_ResetPrimaryChannel();
                }
                else
                {
                    ev.Player.VC_SetPrimaryChannel(VoiceChatChannel.Mimicry);
                }
            }
        }
        private static void Player_InteractingDoor(Exiled.Events.EventArgs.Player.InteractingDoorEventArgs ev)
        {
            if (ev.Player.GetSide() == Side.Scp && ev.Door.IsCheckpoint)
            {
                ev.IsAllowed = true;
            }
        }

        private static void Player_Left(LeftEventArgs ev)
        {
            CustomCharacter.AllCharacters.RemoveAll(x => x.UserId == ev.Player.UserId);
        }

        private static void Player_Verified(VerifiedEventArgs ev)
        {
            Dictionary<KeyCode, string> keys = new Dictionary<KeyCode, string>()
            {
                {KeyCode.Alpha3, ".ability 0" }, {KeyCode.Alpha4, ".ability 1"}, {KeyCode.Alpha5, ".ability 2"},
                {KeyCode.F9, ".v ty" }, {KeyCode.F10, "v. fd"}
            };
            foreach (var key in keys)
                ev.Player.ReferenceHub.characterClassManager.TargetChangeCmdBinding(key.Key, key.Value);
        }
       
        private static void Server_RespawningTeam(Exiled.Events.EventArgs.Server.RespawningTeamEventArgs ev)
        {
            if (Round.IsEnded)
            {
                return;
            }
            if (!CustomCharacter.Waves.ContainsKey(ev.NextKnownTeam))
            {
                CustomCharacter.Waves.Add(ev.NextKnownTeam, 0);
            }
            CustomCharacter.Waves[ev.NextKnownTeam]++;
            Log.Info("第" + CustomCharacter.Waves[ev.NextKnownTeam] + "波增援已刷新");
            foreach (var key in CustomCharacterPlugin.instance.Manager.AllTypes.Keys)
            {
                if (typeof(ITeamSpawn).IsAssignableFrom(key) && (GameMode.CurrentGameMode.GetType() == GameMode.DefaultMode ||
                    key.GetCustomAttribute<RoleInfoAttribute>()?.AvailableGameMode.Contains(GameMode.CurrentGameMode.GetType()) == true))
                {
                    var inst = (ITeamSpawn)Activator.CreateInstance(key, 0);
                    int wave = 0;
                    foreach (var x in CustomCharacter.Waves)
                    {
                        if (x.Key == inst.SpawnType || inst.SpawnType == SpawnableTeamType.None)
                            wave += x.Value;
                    }
                    if ((ev.NextKnownTeam == inst.SpawnType || inst.SpawnType == SpawnableTeamType.None) &&
                        (wave <= inst.MaxWaves || inst.MaxWaves == 0))
                    {
                        Timing.CallDelayed(1.0f, delegate ()
                        {
                            Log.Info("尝试生成：" + inst.GetType().Name);
                            inst.OnTeamSpawn(ev.Players);
                        });
                    }
                }
            }
        }
        private static void Server_RestartingRound()
        {
            CustomCharacter.AllCharacters.Clear();
            CustomCharacter.Waves.Clear();
        }

        private static void Server_RoundEnded(Exiled.Events.EventArgs.Server.RoundEndedEventArgs ev)
        {
            foreach (var all in CustomCharacter.AllCharacters)
            {
                all.Role_Deactive();
            }
            CustomCharacter.AllCharacters.Clear();
        }
        private static void Server_RoundStarted()
        {
            Log.Info("开始生成自定义角色");
            List<Player> players = new List<Player>();
            players.AddRange(Player.List.Where(x => GameplayData.GameDatas.FirstOrDefault(y => y.Player == x)?.KeyBinded == true));
            List<Type> available = new List<Type>(CustomCharacterPlugin.instance.Manager.AllTypes.Keys);
            available.RemoveAll(x => !typeof(IRoundStartSpawn).IsAssignableFrom(x) ||
            (GameMode.CurrentGameMode.GetType() != GameMode.DefaultMode &&
            !x.GetCustomAttribute<RoleInfoAttribute>().AvailableGameMode.Contains(GameMode.CurrentGameMode.GetType())));
            for (int i = 0; i < available.Count; i++)
            {
                var instance = (IRoundStartSpawn)Activator.CreateInstance(available[i], 0);
                if (instance.MinPlayers >= Player.List.Count())
                {
                    available.RemoveAt(i);
                    i--;
                }
            }
            while (CustomRoleReservation.Reservations.Count > 0 && players.Count > 0)
            {
                var res = CustomRoleReservation.Reservations.FirstOrDefault();
                CustomRoleReservation.Reservations.Remove(res);
                Player player = Player.Get(res.UserId);
                if (player != null)
                {
                    if (available.Contains(res.RoleType))
                    {
                        players.Remove(player);
                        available.Remove(res.RoleType);
                        CustomCharacter.SpawnPlayer(player, res.RoleType);
                        res.Success(res.UserId);
                    }
                    else
                    {
                        res.Failed(res.UserId);
                    }
                }
            }
            while (available.Count > 0 && players.Count > 0)
            {
                var role = available[UnityEngine.Random.Range(0, available.Count)];
                available.Remove(role);
                var players_ = players.Where(x => x.Role.Type == role.GetCustomAttribute<RoleInfoAttribute>().OriginRole);
                if (players_.Count() > 0)
                {
                    Player player = players_.ElementAt(UnityEngine.Random.Range(0, players_.Count()));
                    players.Remove(player);
                    CustomCharacter.SpawnPlayer(player, role);
                }
            }
            CustomRoleReservation.Reservations.ForEach(x => x.Failed(x.UserId));
            CustomRoleReservation.Reservations.Clear();
            Log.Info("自定义角色生成完毕");
        }
    }
}
